﻿using System;
using System.Collections.Specialized;
using System.Text;
using System.Web;
using BSU.CSCE.Utilities;
using BSU.CSCE.Web.Models;

namespace BSU.CSCE.Web.Controls.Pager
{
    public class Pager
    {
        private readonly PagerViewModel _model;
        private readonly HttpRequestBase _request;
        private string _pageQueryName = "page";

        private string _paginationFirst = "First";
        private string _paginationLast = "Last";
        private string _paginationNext = "Next";
        private string _paginationPrev = "Prev";

        private int _showingPagesCount = 7;

        /// <summary>
        /// Creates a new instance of the Pager class.
        /// </summary>
        /// <param name="model">The PagerViewModel datasource</param>
        /// <param name="request">The current HTTP Request</param>
        public Pager(PagerViewModel model, HttpRequestBase request)
        {
            _model = model;
            _request = request;
        }

        public Pager(PagerViewModel model, HttpRequestBase request,
                     string paginationFirstText, string paginationPrevText, string paginationNextText,
                     string paginationLastText)
        {
            _model = model;
            _request = request;

            _paginationFirst = paginationFirstText;
            _paginationPrev = paginationPrevText;
            _paginationNext = paginationNextText;
            _paginationLast = paginationLastText;
        }

        public Pager QueryParam(string queryStringParam)
        {
            _pageQueryName = queryStringParam;
            return this;
        }

        public Pager Format(string format)
        {
            return this;
        }

        public Pager First(string first)
        {
            _paginationFirst = first;
            return this;
        }

        public Pager Previous(string previous)
        {
            _paginationPrev = previous;
            return this;
        }

        public Pager Next(string next)
        {
            _paginationNext = next;
            return this;
        }

        public Pager Last(string last)
        {
            _paginationLast = last;
            return this;
        }

        public int TotalItems
        {
            get
            {
                return _model.TotalRowCount;
            }
        }

        public int PageSize
        {
            get
            {
                return _model.PageSize;
            }
        }

        public int PageNumber
        {
            get
            {
                return _model.PageNumber;
            }
        }

        public int TotalPages
        {
            get { return (int)Math.Ceiling(((double)TotalItems) / PageSize); }
        }

        public int FirstItem
        {
            get
            {
                return ((PageNumber - 1) * PageSize) + 1;
            }
        }

        public int LastItem
        {
            get
            {
                return Math.Min(FirstItem + PageSize - 1, TotalItems);
            }
        }

        public bool HasPreviousPage
        {
            get { return PageNumber > 1; }
        }

        public bool HasNextPage
        {
            get { return PageNumber < TotalPages; }
        }

        public override string ToString()
        {
            if (TotalItems == 0)
            {
                return null;
            }

            var builder = new StringBuilder();

            builder.Append("<div class='pagination'>");
            builder.Append("<ul>");
            builder.Append("<li class='pagination-first'>");
            builder.Append(CreateFirstLink());
            builder.Append("</li>");
            builder.Append("<li class='pagination-prev'>");
            builder.Append(CreatePrevLink());
            builder.Append("</li>");
            builder.Append(CreatePagesNumberLinks());
            builder.Append("<li class='pagination-next'>");
            builder.Append(CreateNextLink());
            builder.Append("</li>");
            builder.Append("<li class='pagination-last'>");
            builder.Append(CreateLastLink());
            builder.Append("</li>");
            builder.Append("</ul>");
            builder.Append(@"</div>");

            return builder.ToString();
        }

        private StringBuilder CreatePagesNumberLinks()
        {
            StringBuilder builder = new StringBuilder();
            int startPageIndex = 1;
            int endPageIndex = 1;
            if (TotalPages < _showingPagesCount)
            {
                endPageIndex = TotalPages;
            }
            else
            {
                startPageIndex = PageNumber - 3;
                if (startPageIndex <= 1)
                {
                    startPageIndex = 1;
                    endPageIndex = _showingPagesCount;
                }
                else
                {
                    endPageIndex = PageNumber + 3;
                    if (endPageIndex >= TotalPages)
                    {
                        endPageIndex = TotalPages;
                        startPageIndex = TotalPages - _showingPagesCount + 1;
                    }
                }
            }

            bool isFirstLiClassAdded = false;
            if (startPageIndex != 1)
            {
                builder.Append("<li class='first'>...</li>");
                isFirstLiClassAdded = true;
            }
            for (int i = startPageIndex; i <= endPageIndex; i++)
            {
                if (!isFirstLiClassAdded && i == startPageIndex)
                {
                    builder.Append("<li class='first'>");
                    isFirstLiClassAdded = true;
                }
                else
                {
                    builder.Append("<li>");
                }
                if (i == PageNumber)
                {
                    builder.Append(i);
                }
                else
                {
                    builder.Append(CreatePageLink(i, i.ToString()));
                }
                builder.Append("</li>");
            }
            if (endPageIndex != TotalPages)
            {
                builder.Append("<li>...</li>");
            }


            return builder;
        }

        private StringBuilder CreateLastLink()
        {
            var builder = new StringBuilder();
            if (PageNumber < TotalPages)
            {
                builder.Append(CreatePageLink(TotalPages, _paginationLast));
            }
            else
            {
                builder.Append(_paginationLast);
            }

            return builder;
        }

        private StringBuilder CreateNextLink()
        {
            var builder = new StringBuilder();
            if (HasNextPage)
            {
                builder.Append(CreatePageLink(PageNumber + 1, _paginationNext));
            }
            else
            {
                builder.Append(_paginationNext);
            }

            return builder;
        }

        private StringBuilder CreatePrevLink()
        {
            StringBuilder builder = new StringBuilder();
            if (HasPreviousPage)
            {
                builder.Append(CreatePageLink(PageNumber - 1, _paginationPrev));
            }
            else
            {
                builder.Append(_paginationPrev);
            }
            return builder;
        }

        private StringBuilder CreateFirstLink()
        {
            var builder = new StringBuilder();
            if (PageNumber == 1)
            {
                builder.Append(_paginationFirst);
            }
            else
            {
                builder.Append(CreatePageLink(1, _paginationFirst));
            }
            return builder;
        }

        private string CreatePageLink(int pageNumber, string text)
        {
            NameValueCollection queryString =
                UriUtil.AddParamToQueryString(_request.QueryString, _pageQueryName, pageNumber.ToString());

            string filePath = _request.FilePath;
            return string.Format("<a href=\"{0}{1}\">{2}</a>",
                                            filePath,
                                            queryString.ToQueryString(),
                                            text);
        }
    }
}
